package com.zhouyu.mysql;

import com.zhouyu.mysql.core.*;
import com.zhouyu.mysql.dict.DictColumn;
import com.zhouyu.mysql.dict.DictTable;
import com.zhouyu.mysql.dict.SystemDict;
import com.zhouyu.mysql.page.FspHdrPage;
import com.zhouyu.mysql.page.IndexPage;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.alter.Alter;
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.FromItemVisitorAdapter;
import net.sf.jsqlparser.statement.select.PlainSelect;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import static com.zhouyu.mysql.page.IndexPage.PAGE_NEW_SUPREMUM;

/**
 * 大都督周瑜（我的微信: dadudu6789）
 */
public class HaInnodb {

    public void createTable(CreateTable createTableStatement) {

        String tableName = createTableStatement.getTable().getName();

        if (SystemDict.getInstance().getNameTables().containsKey(tableName)) {
            throw new RuntimeException("表已经存在");
        }

        // 生成一个新id
        int tableId = SystemDict.getInstance().addMaxTableId();
        int spaceId = SystemDict.getInstance().addMaxSpaceId();

        // 创建t1.ibd文件，返回文件路径
        Path tableSpacePath = SpaceUtil.createUserTableSpace(tableName);

        DictTable dictTable = new DictTable();
        dictTable.setTableId(tableId);
        dictTable.setSpaceId(spaceId);
        dictTable.setTableName(tableName);
        dictTable.setPath(tableSpacePath.toString());

        List<DictColumn> dictColumnList = new ArrayList<>();
        List<ColumnDefinition> columnDefinitions = createTableStatement.getColumnDefinitions();
        for (int i = 0; i < columnDefinitions.size(); i++) {
            ColumnDefinition columnDefinition = columnDefinitions.get(i);

            DictColumn dictColumn = new DictColumn();
            dictColumn.setTableId(tableId);
            dictColumn.setName(columnDefinition.getColumnName());
            String dataType = columnDefinition.getColDataType().getDataType();
            dictColumn.setType(dataType);
            dictColumn.setColNo(i);
            if ("int".equals(dataType)) {
                dictColumn.setLen(4);
            } else {
                // 实际应该解析出varchar(11)中的11，然后还要知道编码集，才能算出字段长度
                // 这里就直接写死了，方便模拟
                dictColumn.setLen(2);
            }
            dictColumnList.add(dictColumn);
        }

        dictTable.setDictColumnList(dictColumnList);

        // 将当前创建的表元数据添加到数据字典
        SystemDict.getInstance().getNameTables().put(tableName, dictTable);
        SystemDict.getInstance().getIdTables().put(tableId, dictTable);
        SystemDict.getInstance().getSpaceIdTables().put(spaceId, dictTable);

        // 把SystemDict对象持久化
        SystemDict.getInstance().serialize();

        // 初始化FspHdrPage
        FspHdrPage fspHdrPage = SpaceUtil.getFspHdrPage(spaceId);
        fspHdrPage.init_file_header(spaceId, 0);
        fspHdrPage.fil_page_set_type(8);  // 源码中8表示FSP_HDR
        fspHdrPage.set_fsp_size(1);       // 当前表空间中只有1页，pageNo为0
        PageUtil.flushPage(fspHdrPage);   // 记得把页的修改持久化到ibd文件中去
    }

    public void insert(Insert insertStatement) {

        // 插入到哪个表空间的哪一页
        String tableName = insertStatement.getTable().getName();
        DictTable dictTable = SystemDict.getInstance().getNameTables().get(tableName);

        // 将insert转成DTuple，里面包含了插入的字段和数据
        DTuple dTuple = DTupleUtil.convert(insertStatement);

        // 先写死页号，后面实现B+树后，通过B+来定位要插入的pageNo，并且还要判断页是否满了
        int pageNo = 1;
        if (SpaceUtil.getFspHdrPage(dictTable.getSpaceId()).get_fsp_size() == 1) {
            pageNo = PageUtil.createPage(dictTable.getSpaceId());
        }
        IndexPage indexPage = PageUtil.readPage(dictTable.getSpaceId(), pageNo);

        // 插入记录
        PageUtil.insert_row(indexPage, dTuple);
    }

    public SelectOneResult select_one(PlainSelect selectStatement, PageCur pageCur) {

        // 获取表名
        final String[] tableNameArray = new String[1];
        selectStatement.getFromItem().accept(new FromItemVisitorAdapter() {
            @Override
            public void visit(Table table) {
                tableNameArray[0] = table.getName();
            }
        });
        String tableName = tableNameArray[0];

        DictTable dictTable = SystemDict.getInstance().getNameTables().get(tableName);

        // 先写死
        IndexPage indexPage = PageUtil.readPage(dictTable.getSpaceId(), 1);

        int next_rec = RecUtil.rec_get_next_offs(indexPage, pageCur.getRec());

        if (next_rec == PAGE_NEW_SUPREMUM) {
            return SelectOneResult.builder().endOfIndex(true).build(); //表示所有记录都遍历完了
        }

        HashMap<String, Object> result = RecUtil.getRecContent(indexPage, next_rec);
        PageCur nextPageCur = new PageCur();
        nextPageCur.setPageNo(indexPage.fil_page_get_page_offset());
        nextPageCur.setRec(next_rec);

        return SelectOneResult.builder()
                .endOfIndex(false)
                .recContent(result)
                .pageCur(nextPageCur)
                .build();


    }

    public void alter(Alter alterStatement) {

    }
}
